<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>手写一个Promise</title>
  </head>
  <body>
    <script>
      // 1. 基本架构
      function myPromise(excutor) {
        let self = this;
        self.status = "pending"; // 初始状态
        self.value = null; // 成功的状态
        self.reason = null; // 失败的原因

        self.onFulfilledCallbacks = []; // 6声明一个容器 用来先不执行保存函数
        self.onRejectedCallbacks = []; // 6声明一个容器 用来先不执行保存函数

        // 成功的回调
        function resolve(value) {
          // 4 状态处理
          if (self.status === "pending") {
            self.value = value; // 保存成功的结果
            self.status = "fulfilled"; // 改变状态
            // 7 状态改变 依次用遍历取出 (发布)
            self.onFulfilledCallbacks.forEach((item) => item(value));
          }
        }
        // 失败的回调
        function reject(reason) {
          if (self.status === "pending") {
            self.reason = reason;
            self.status = "rejected";
            // 7 状态改变 依次取出 (发布)
            self.onRejectedCallbacks.forEach((item) => item(reason));
          }
        }

        // 3. 立即执行这两个方法(执行器)
        try {
          excutor(resolve, reject);
        } catch (error) {
          console.log(error);
        }
      }

      // 2 .then方法（传两个参数） 每个Promise都有一个.then方法  可以挂载在原型上合理
      myPromise.prototype.then = function (onFulfilled, onRejected) {
        // 确定.then传过来的是一个方法 如果不是就用自己定义的这个方法 用三目运算符判断
        // 5. 状态改变 走.then
        onFulfilled =
          typeof onFulfilled === "function"
            ? onFulfilled
            : function (data) {
                resolve(data);
              };
        onRejected =
          typeof onRejected === "function"
            ? onRejected
            : function (err) {
                throw err;
              };
        // 6 发布订阅模式  (订阅)
        console.log(this.status); // 输出状态还是penging没有改变 也就不会执行下一步成功或者失败   如何解决？？？就用发布订阅模式
        if (this.status == "pending") {
          this.onFulfilledCallbacks.push(onFulfilled);
          this.onRejectedCallbacks.push(onRejected);
        }
      };
      // 2.1  先试试这个异步方法是否能打印出来
      let demo = new myPromise((resolve, reject) => {
        console.log("能打印出来吗？？？"); // 不能  需要传入一个执行器
        setTimeout(() => {
          resolve(123);
        }, 4000);
      });
      demo.then((data) => console.log(data)); // 没有两秒后执行出来这个结果，但是也不报错（必然是第4步没有执行，看状态是否改变了，输出状态还是pending没有改变）
    </script>
  </body>
</html>
